﻿using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Modules.Base;
using Modules.System.Attachment.EventModules;
using PmSoft;
using PmSoft.ApplicationContext;
using PmSoft.Events;
using PmSoft.Exceptions;
using PmSoft.FileStorage;

namespace Modules.System.Attachment;

[UseDI(ServiceLifetime.Scoped)]
public class AttachmentService
{
    private readonly IApplicationContext applicationContext;
    private readonly AttachmentRepository attachmentRepository;
    private readonly IEventBus eventBus;

    private const string tempDirectory = "temps";

    public AttachmentService(IApplicationContext applicationContext,
        AttachmentRepository attachmentRepository, IEventBus eventBus, IFileStorage fileStorage)
    {
        this.applicationContext = applicationContext;
        this.attachmentRepository = attachmentRepository;
        this.eventBus = eventBus;
    }

    static AttachmentService()
    {
        string tempPath = Path.Combine(Environment.CurrentDirectory, tempDirectory);
        if (!Directory.Exists(tempPath))
            Directory.CreateDirectory(tempPath);
    }

    /// <summary>
    /// 获取附件信息
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public AttachmentInfo? GetAttachmentInfo(string id)
    {
        return attachmentRepository.Get(id);
    }

    /// <summary>
    /// 上传临时附件
    /// </summary>
    /// <param name="formFile"></param>
    /// <returns></returns>
    /// <exception cref="BusinessException"></exception>
    public async Task<string> CreateTemporaryAsync(IFormFile formFile)
    {
        if (formFile.Length == 0)
            throw new BusinessException("上传文件为空");

        string orgFileName = Path.GetFileName(formFile.FileName);
        string tempId = Guid.NewGuid().ToString().Replace("-", "");
        string extension = Path.GetExtension(orgFileName).ToLower();
        extension = (extension.StartsWith(".") ? extension : "." + extension);
        if (!new List<string> { ".doc", ".docx", ".xls", ".xlsx", ".pdf", ".jpg", ".png" }.Exists(i => i == extension))
        {
            throw new BusinessException("不支持的上传文件类型");
        }
        if (formFile.Length > 5242880)
        {
            throw new BusinessException("文件大小不能超过5M");
        }
        string saveFileName = tempId + extension;

        //插入数据组装
        AttachmentInfo attachment = new AttachmentInfo();
        attachment.Id = tempId;
        attachment.Name = saveFileName;
        attachment.FriendlyName = orgFileName;
        attachment.Ip = applicationContext.ClientIp ?? string.Empty;
        attachment.FileLength = formFile.Length;
        attachment.IsTemporary = true;
        attachment.ContentType = formFile.ContentType;
        attachment.MediaType = GetMediaType(formFile.ContentType);
        attachment.CreateTime = DateTime.Now;
        attachment.Discription = formFile.ContentDisposition;
        attachmentRepository.Insert(attachment);

        var stream = formFile.OpenReadStream();
        byte[] buffer = new byte[stream.Length];
        await stream.ReadAsync(buffer, 0, (int)stream.Length);
        string tempPath = Path.Combine(Environment.CurrentDirectory, tempDirectory, saveFileName);
        await File.WriteAllBytesAsync(tempPath, buffer);

        return tempId;
    }

    /// <summary>
    /// 将临时附件上传到MinIO
    /// </summary>
    /// <param name="relationship"></param>
    public void ToggleTemporaryAttachment(IAttachmentRelationship relationship)
    {
        ToggleTemporaryAttachments(new List<IAttachmentRelationship> { relationship });
    }

    /// <summary>
    /// 将临时附件上传到MinIO
    /// </summary>
    /// <param name="relationships"></param>
    public void ToggleTemporaryAttachments(IEnumerable<IAttachmentRelationship> relationships)
    {
        eventBus.PublishTo(this, new PublishAttachmentEventArgs(applicationContext, relationships));
    }

    /// <summary>
    /// 依据EntityId集合组装成实体集合
    /// </summary>
    /// <param name="attachmentIds"></param>
    /// <returns></returns>
    public IEnumerable<AttachmentInfo> GetAttachmentInfos(IEnumerable<string> attachmentIds)
    {
        return attachmentRepository.PopulateEntitiesByEntityIds(attachmentIds);
    }

    public void Update(AttachmentInfo attachmentInfo)
    {
        attachmentRepository.Update(attachmentInfo);
    }

    /// <summary>
    /// 查询所有过期的临时附件
    /// </summary>
    /// <returns></returns>
    public IEnumerable<AttachmentInfo> GetAttachmentInfosByExpiredTemporary(int hours = 12)
    {
        return attachmentRepository.GetAttachmentInfosByExpiredTemporary(hours);
    }

    /// <summary>
    /// 删除临时附件
    /// </summary>
    /// <param name="attachmentInfo"></param>
    /// <returns></returns>
    public bool DeleteTemporary(AttachmentInfo attachmentInfo)
    {
        if (!attachmentInfo.IsTemporary)
            return false;

        string tempPath = Path.Combine(Environment.CurrentDirectory, tempDirectory, attachmentInfo.Name);
        try
        {
            if (File.Exists(tempPath))
                File.Delete(tempPath);
        }
        catch { }

        return Delete(attachmentInfo);
    }

    /// <summary>
    /// 删除附件
    /// </summary>
    /// <param name="attachmentInfo"></param>
    private bool Delete(AttachmentInfo attachmentInfo)
    {
        return attachmentRepository.Delete(attachmentInfo) > 0;
    }

    //public void DeletedByIds(IEnumerable<string> attachmentIds)
    //{
    //    foreach (var id in attachmentIds)
    //    {
    //        Delete(id);
    //    }
    //}

    /// <summary>
    /// 依据MIME获取MediaType
    /// </summary>
    /// <param name="contentType">附件MIME类型</param>
    /// <returns></returns>
    public static MediaType GetMediaType(string contentType)
    {
        if (contentType == null)
            return MediaType.Other;
        var extensionType = MimeTypeConfiguration.GetExtension(contentType);
        switch (extensionType)
        {
            case "txt":
            case "rtf":
            case "doc":
            case "docx":
            case "wps":
            case "pptx":
            case "ppt":
            case "pps":
            case "xls":
            case "xlsx":
            case "pdf":
                return MediaType.Document;//可在线预览
            case "jpg":
            case "png":
            case "bmp":
            case "gif":
                return MediaType.Image;

            case "flv":
            case "rmvb":
            case "mp4":
            case "3gp":
            case "mpeg":
            case "wmv":
            case "mov":
            case "avi":
            case "asf":
                return MediaType.Video;

            case "zip":
            case "rar":
                return MediaType.Compressed;

            case "swf":
                return MediaType.Flash;

            case "mp3":
            case "wav":
            case "rm":
                return MediaType.Audio;

            default:
                return MediaType.Other;
        }
    }
}